package com.zrc.japktool.ui.view;

import javafx.application.Platform;
import javafx.scene.input.DragEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class WebLogView extends StackPane {
    private final WebView webView;
    private final WebEngine webEngine;
    private boolean needScrollToBottom = true;

    public enum LogLevel {
        //INFO("#2196F3"),    // 蓝色
        INFO("#8A8A8A"),    // 灰色
        WARN("#FFC107"),    // 黄色
        ERROR("#F44336"),   // 红色
        DEBUG("#4CAF50"),   // 绿色
        TIP("#9C27B0");     // 紫色

        public final String color;
        LogLevel(String color) {
            this.color = color;
        }
    }

    private static final DateTimeFormatter TIME_FORMATTER =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    public WebLogView() {
        this.webView = new WebView();
        this.webEngine = webView.getEngine();

        // 1. WebView尺寸约束：完全跟随StackPane，避免无限扩展
        webView.setPrefSize(0, 0); // 优先继承父容器尺寸
        webView.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); // 允许扩展到父容器边界
        webView.setMinSize(0, 0);
        webView.setZoom(1.0);

        // 2. 禁用WebView自身滚动和边框，避免与内部HTML冲突
        webView.setStyle("-fx-overflow: hidden; -fx-background-color: transparent; -fx-border-width: 0;");

        // GPU渲染兼容性配置：解决部分环境WebView显示异常
        System.setProperty("prism.order", "sw");
        System.setProperty("javafx.webview.disableGPU", "true");

        // 拖拽事件透传：确保父容器能接收拖拽事件
        this.addEventFilter(DragEvent.ANY, event -> {
            if (event.getEventType() == DragEvent.DRAG_OVER || event.getEventType() == DragEvent.DRAG_DROPPED) {
                event.consume();
                if (this.getParent() != null) {
                    event.fireEvent(this.getParent(), event.copyFor(event.getSource(), this.getParent()));
                }
            }
        });

        // StackPane自身样式：明确边界，与内部HTML背景统一（无额外内边距）
        this.setStyle("""
                -fx-border-color: #d0d0d0;
                -fx-border-width: 1px;
                -fx-border-radius: 3px;
                -fx-padding: 0; /* 关键：父容器无内边距，避免高度被压缩 */
                -fx-background-color: #f5f5f5;
                """);

        getChildren().add(webView);
        initialize();

        // 3. 尺寸同步：监听StackPane变化，实时同步给WebView和HTML（修复高度同步时机）
        this.widthProperty().addListener((obs, oldW, newW) -> {
            if (newW.doubleValue() > 0) {
                webView.setPrefWidth(newW.doubleValue());
                syncHtmlSize(newW.doubleValue(), this.getHeight());
            }
        });

        this.heightProperty().addListener((obs, oldH, newH) -> {
            if (newH.doubleValue() > 0) {
                webView.setPrefHeight(newH.doubleValue());
                // 延迟10ms同步高度：等待WebView尺寸完全生效（解决渲染延迟导致的偏差）
                Platform.runLater(() -> {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    syncHtmlSize(this.getWidth(), newH.doubleValue());
                });
            }
        });

        // WebView加载完成后初始化：确保尺寸和滚动状态正确（强制同步高度）
        webEngine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
            if (newState == javafx.concurrent.Worker.State.SUCCEEDED) {
                Platform.runLater(() -> {
                    // 强制WebView尺寸与StackPane完全一致
                    webView.setPrefWidth(getWidth());
                    webView.setPrefHeight(getHeight());
                    // 延迟同步HTML尺寸，确保WebView渲染完成
                    Platform.runLater(() -> {
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                        syncHtmlSize(getWidth(), getHeight());
                        forceScrollToBottom();
                    });
                });
            }
        });
    }

    // 初始化HTML内容：核心修复【日志消息颜色与时间/等级统一】
    private void initialize() {
        String initialHtml = """
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <style>
                    /* HTML根节点：完全填充WebView，无任何冗余边距/内边距 */
                    html, body {
                        width: 100%;
                        height: 100%;
                        margin: 0;
                        padding: 0;
                        box-sizing: border-box; /* 确保尺寸计算不包含冗余 */
                        overflow: hidden; /* 禁用外层滚动，避免高度被侵占 */
                        background-color: #f5f5f5;
                    }
                    /* 日志容器：修复底部间隙，滚动条完全贴近底边框 */
                    #logBody {
                        font-family: monospace;
                        background-color: #f5f5f5;
                        width: 100%; /* 宽度完全填充父容器 */
                        height: 100%; /* 高度完全填充父容器（无额外减法） */
                        padding: 10px; /* 内边距通过box-sizing包含在100%高度内 */
                        box-sizing: border-box; /* 关键：内边距不额外增加高度，避免底部溢出 */
                        overflow-y: auto; /* 纵向滚动条紧贴容器边界 */
                        overflow-x: hidden; /* 禁用横向滚动，防止高度偏差 */
                        line-height: 1.2;
                        font-size: 12px;
                        margin: 0; /* 无任何外边距，避免底部间隙 */
                    }
                    /* 滚动条样式：固定尺寸，避免滚动条自身占位偏差 */
                    ::-webkit-scrollbar { 
                        width: 8px; 
                        height: 8px; 
                    }
                    ::-webkit-scrollbar-track { 
                        background: #f5f5f5; 
                        border-radius: 4px; 
                        margin: 0; /* 滚动条轨道无外边距 */
                    }
                    ::-webkit-scrollbar-thumb { 
                        background: #c1c1c1; 
                        border-radius: 4px; 
                    }
                    ::-webkit-scrollbar-thumb:hover { 
                        background: #a1a1a1; 
                    }
                    /* 日志条目样式：优化排版，避免影响容器高度 */
                    .log-entry { 
                        margin: 2px 0; 
                        padding: 3px 5px; 
                        border-radius: 2px; 
                        white-space: pre-wrap; /* 长日志自动换行，不撑高容器 */
                        word-break: break-all; 
                    }
                    .timestamp { font-weight: 500; margin-right: 10px; }
                    .level { font-weight: bold; margin-right: 10px; padding: 0 4px; border-radius: 3px; color: white; }
                    /*日志消息默认样式（后续通过JS动态设置颜色） */
                    .message { color: inherit; } /* 继承父元素颜色，确保与时间/等级统一 */
                </style>
            </head>
            <body>
                <div id="logBody"></div>
            </body>
            <script>
                const logBody = document.getElementById('logBody');
                let scrollContainer = logBody;
                
                /**
                 * 添加日志条目，返回当前滚动状态
                 * 核心修改：为日志消息（messageSpan）设置与时间戳/等级相同的颜色
                 */
                function addLogEntry(timestamp, level, levelColor, message) {
                    const fragment = document.createDocumentFragment();
                    const entry = document.createElement('div');
                    entry.className = 'log-entry';
                    
                    const timeSpan = document.createElement('span');
                    timeSpan.className = 'timestamp';
                    timeSpan.textContent = timestamp;
                    timeSpan.style.color = levelColor; // 时间戳颜色：等级色
                    
                    const levelSpan = document.createElement('span');
                    levelSpan.className = 'level';
                    levelSpan.style.backgroundColor = levelColor; // 等级标签背景：等级色
                    levelSpan.textContent = level;
                    
                    const messageSpan = document.createElement('span');
                    messageSpan.className = 'message';
                    messageSpan.textContent = message;
                    // 关键修复：日志消息颜色 = 等级色（与时间戳、等级标签保持一致）
                    messageSpan.style.color = levelColor; 
                    
                    entry.appendChild(timeSpan);
                    entry.appendChild(levelSpan);
                    entry.appendChild(messageSpan);
                    fragment.appendChild(entry);
                    
                    logBody.appendChild(fragment);
                    logBody.offsetHeight; // 强制DOM渲染，避免尺寸延迟导致的底部间隙
                    
                    return getScrollState();
                }
                
                /**
                 * 强制滚动到底部（精准计算底部位置，避免间隙）
                 */
                function forceScrollToBottom() {
                    if (!scrollContainer) return false;
                    
                    // 精准计算滚动条底部位置：scrollHeight - clientHeight（无任何偏移）
                    const targetScrollTop = scrollContainer.scrollHeight - scrollContainer.clientHeight;
                    scrollContainer.scrollTop = Math.max(targetScrollTop, 0);
                    
                    // 验证是否完全到底（误差允许1px，避免渲染精度问题）
                    return scrollContainer.scrollTop >= targetScrollTop - 1;
                }
                
                /**
                 * 获取当前滚动状态（是否在底部、滚动位置等）
                 */
                function getScrollState() {
                    if (!scrollContainer) return { isAtBottom: false };
                    
                    const scrollTop = scrollContainer.scrollTop;
                    const scrollHeight = scrollContainer.scrollHeight;
                    const clientHeight = scrollContainer.clientHeight;
                    const isAtBottom = scrollTop >= scrollHeight - clientHeight - 1;
                    
                    return { scrollTop, scrollHeight, clientHeight, isAtBottom };
                }
                
                /**
                 * 清空所有日志，重置滚动条（确保滚动条回到顶部且无底部间隙）
                 */
                function clearLogs() {
                    if (scrollContainer) {
                        scrollContainer.innerHTML = '';
                        scrollContainer.scrollTop = 0;
                        // 清空后强制同步尺寸，避免残留间隙
                        scrollContainer.style.height = scrollContainer.parentElement.clientHeight + 'px';
                    }
                    return true;
                }
                
                /**
                 * 同步日志容器尺寸（核心修复：高度完全匹配WebView，无底部间隙）
                 */
                function setContainerSize(width, height) {
                    if (scrollContainer && width > 0 && height > 0) {
                        // 关键：宽度/高度直接使用WebView尺寸，不额外减法（内边距通过box-sizing包含）
                        scrollContainer.style.width = width + 'px';
                        scrollContainer.style.height = height + 'px';
                        // 强制DOM重绘，确保尺寸立即生效
                        scrollContainer.offsetHeight;
                    }
                }
            </script>
            </html>
            """;
        webEngine.loadContent(initialHtml);
    }

    /**
     * 核心日志方法：添加指定级别日志
     */
    public void log(LogLevel level, String message) {
        if (level == null || message == null || message.trim().isEmpty()) {
            return;
        }

        Platform.runLater(() -> {
            if (webEngine.getLoadWorker().getState() != javafx.concurrent.Worker.State.SUCCEEDED) {
                return;
            }

            String timestamp = LocalDateTime.now().format(TIME_FORMATTER);
            JSObject window = (JSObject) webEngine.executeScript("window");
            if (window == null) {
                return;
            }

            try {
                // 添加日志并获取滚动状态（颜色参数已通过level.color传递给JS）
                JSObject scrollState = (JSObject) window.call("addLogEntry", timestamp, level.name(), level.color, message);
                boolean isAtBottom = (boolean) scrollState.getMember("isAtBottom");

                // 自动滚动到底部（仅当需要时）
                if (needScrollToBottom && !isAtBottom) {
                    window.call("forceScrollToBottom");
                }

                // 同步尺寸，确保滚动条位置正确
                syncHtmlSize(getWidth(), getHeight());
            } catch (Exception e) {
                if (needScrollToBottom) {
                    forceScrollToBottom();
                }
            }
        });
    }

    /**
     * 对外暴露：强制滚动到底部
     */
    public void forceScrollToBottom() {
        Platform.runLater(() -> {
            if (webEngine.getLoadWorker().getState() == javafx.concurrent.Worker.State.SUCCEEDED) {
                webEngine.executeScript("forceScrollToBottom()");
            }
        });
    }

    /**
     * 同步HTML容器尺寸：调用JS方法更新日志容器大小（确保高度无偏差）
     */
    private void syncHtmlSize(double width, double height) {
        if (width <= 0 || height <= 0 || webEngine.getLoadWorker().getState() != javafx.concurrent.Worker.State.SUCCEEDED) {
            return;
        }

        Platform.runLater(() -> {
            JSObject window = (JSObject) webEngine.executeScript("window");
            if (window != null) {
                // 传递StackPane的实际尺寸（已同步给WebView），无额外偏移
                window.call("setContainerSize", width, height);
            }
        });
    }

    /**
     * 快捷方法：添加INFO级别日志
     */
    public void info(String message) {
        log(LogLevel.INFO, message);
    }

    /**
     * 快捷方法：添加WARN级别日志
     */
    public void warn(String message) {
        log(LogLevel.WARN, message);
    }

    /**
     * 快捷方法：添加ERROR级别日志
     */
    public void error(String message) {
        log(LogLevel.ERROR, message);
    }

    /**
     * 快捷方法：添加DEBUG级别日志
     */
    public void debug(String message) {
        log(LogLevel.DEBUG, message);
    }

    /**
     * 快捷方法：添加TIP级别日志
     */
    public void tip(String message) {
        log(LogLevel.TIP, message);
    }

    /**
     * 清空所有日志
     */
    public void clear() {
        Platform.runLater(() -> {
            if (webEngine.getLoadWorker().getState() == javafx.concurrent.Worker.State.SUCCEEDED) {
                JSObject window = (JSObject) webEngine.executeScript("window");
                if (window != null) {
                    window.call("clearLogs");
                }
                needScrollToBottom = true;
            }
        });
    }

    /**
     * 获取内部WebView实例（谨慎使用，避免破坏封装）
     */
    public WebView getWebView() {
        return webView;
    }

    /**
     * 设置是否自动滚动到底部（true：日志时自动滚底；false：保持当前位置）
     */
    public void setAutoScroll(boolean autoScroll) {
        this.needScrollToBottom = autoScroll;
    }
}
